#!/user/bin/env python3
# -*- coding: utf-8 -*-
"""
--------------------------------------
    Author:     JiChao_Song
    Date  :     2022/1/6 13:28
    Desc  :
--------------------------------------
"""
from django.core.paginator import Paginator
from django.urls import path
from django.utils.decorators import method_decorator
from django_http_log.common.request import BaseAPIView
from django_http_log.common.response import SuccessResponse, SystemExceptionResponse, CommonResponse, \
    ParamsErrorResponse

from common.decorator.token_decorator import isAuthentication, Authentication
from common.enums.project_enums import ProjectStatusEnums
from common.enums.response_enums import CommonResultEnums
from common.utils.log_utils import logger
from common.utils.other_utils import get_time, queryDict, get_enum_str_list, get_enum_key_list
from common.utils.token_utils import RequestAuthTokenUtil
from person.models import Project, Person, ProjectPerson
from person.serializers.person import PersonListSerializer
from person.serializers.project import ProjectSerializer, ProjectListSerializer
from platform_auth.settings import APIDOC_DECORATOR
from django.db import transaction, connection


class ProjectBaseAPIView(BaseAPIView):
    Model = Project

    serializer_class = ProjectSerializer


class ProjectAddAPIView(ProjectBaseAPIView):
    """
    项目新增
    """

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/add', summary = '项目新增')
    @APIDOC_DECORATOR.ApiParams(value = 'projectName', require = True, type = 'string', desc = '项目名称')
    @APIDOC_DECORATOR.ApiParams(value = 'projectIcon', require = False, type = 'string', desc = '项目图标')
    @APIDOC_DECORATOR.ApiParams(value = 'projectDesc', require = False, type = 'string', desc = '项目描述')
    @APIDOC_DECORATOR.ApiParams(value = 'projectStatus', require = False, type = 'int', desc = '项目状态',
                                remark = get_enum_str_list(enumObj = ProjectStatusEnums))
    @APIDOC_DECORATOR.ApiParams(value = 'beginTime', require = False, type = 'int', desc = '项目开始时间', remark = '时间戳')
    @APIDOC_DECORATOR.ApiParams(value = 'endTime', require = False, type = 'int', desc = '项目结算时间', remark = '时间戳')
    @APIDOC_DECORATOR.ApiParams(value = 'remark', type = 'string', desc = '备注')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()
            projectStatus = body.get('projectStatus')
            persons = body.get('persons')
            # 1. 判断项目名称是否存在
            queryset_name = self.Model.objects.filter(projectName = body.get('projectName'), deleted = False)

            if queryset_name.count() != 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_NAME_IS_EXIST)
            # 1.1 判断projectStatus是否合法
            if not isinstance(projectStatus, int):
                return ParamsErrorResponse(message = 'projectStatus参数类型错误')
            if projectStatus not in get_enum_key_list(enumObj = ProjectStatusEnums):
                return ParamsErrorResponse(message = 'projectStatus参数枚举不存在')
            # 1.2 判读那person是否合法
            if not isinstance(persons, list):
                return ParamsErrorResponse(message = 'persons参数类型错误, 期望是一个数组')

            # 2. 保存
            with transaction.atomic():
                Project_data = self.Model.objects.create(
                    projectName = body.get('projectName'),
                    projectIcon = body.get('projectIcon'),
                    projectDesc = body.get('projectDesc'),
                    projectStatus = body.get('projectStatus'),
                    beginTime = body.get('beginTime') if body.get('beginTime') else None,
                    endTime = body.get('endTime') if body.get('endTime') else None,
                    remark = body.get('remark'),
                    creatorId = userId,
                    creatorName = userName,
                )

                for i in persons:
                    ProjectPerson.objects.get_or_create(
                        creatorId = userId,
                        creatorName = userName,
                        projectId = Project_data.id,
                        personId = i
                    )
            # 4. 序列化
            serializer = self.serializer_class(Project_data, exclude = self.exclude_fields)

            return SuccessResponse(result = serializer.data)

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectAddPersonAPIView(ProjectBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/addPerson', summary = '项目成员添加')
    @APIDOC_DECORATOR.ApiParams(value = 'personIds', require = True, type = 'array', desc = '项目名称', example = [1, 2, 3])
    @APIDOC_DECORATOR.ApiParams(value = 'projectId', require = False, type = 'int', desc = '项目图标')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()

            body: dict = request.data.copy()
            personIds = body.get('personIds')
            projectId = body.get('projectId')
            # 判断projectId是否存在
            queryset_id = self.Model.objects.filter(id = projectId, deleted = False)
            if queryset_id.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)

            # 判断personIds列表中的id是否有效
            if not isinstance(personIds, list):
                return ParamsErrorResponse(code = 40002, message = 'personIds参数类型错误')
            queryset = queryDict(sql = f"SELECT * FROM tperson WHERE id IN {tuple(personIds)} "
                                       f"‘and deleted = false;")
            # 有效的用户id
            queryset_person_ids = []

            for i in queryset:
                queryset_person_ids.append(i.id)

            queryset_person = list(set(personIds).difference(set(queryset_person_ids)))

            # personId不存在
            if len(queryset_person) != 0:
                return ParamsErrorResponse(code = 40002, message = f'{"personId = ".join(personIds)}不存在')

            with transaction.atomic():
                queryset_id.update(
                    persons = personIds,
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectListAPIView(ProjectBaseAPIView):
    serializer_class = ProjectListSerializer

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/list', summary = '项目列表')
    @APIDOC_DECORATOR.ApiParams(value = 'projectLeaderId', type = 'int', desc = '项目负责人')
    @APIDOC_DECORATOR.ApiParams(value = 'createEndTime', type = 'int', desc = '创建结束时间')
    @APIDOC_DECORATOR.ApiParams(value = 'createStartTime', type = 'int', desc = '创建开始时间')
    @APIDOC_DECORATOR.ApiParams(value = 'projectStatus', type = 'int', desc = '项目状态',
                                remark = get_enum_str_list(enumObj = ProjectStatusEnums))
    @APIDOC_DECORATOR.ApiParams(value = 'projectName', type = 'string', desc = '项目名称', remark = '模糊查询')
    @APIDOC_DECORATOR.ApiParams(value = 'pageSize', type = 'int', require = True, desc = '每页数量')
    @APIDOC_DECORATOR.ApiParams(value = 'pageIndex', type = 'int', require = True, desc = '页码')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            pageIndex = body.get('pageIndex')
            pageSize = body.get('pageSize')
            projectName = body.get('projectName')
            projectStatus = body.get('projectStatus')
            createStartTime = body.get('createStartTime')
            createEndTime = body.get('createEndTime')
            projectLeaderId = body.get('projectLeaderId')

            queryset_sql_str = 'self.Model.objects.filter(deleted = False,'

            if projectName and projectName != '':
                queryset_sql_str += f" projectDesc__icontains = '{projectName}',"

            if projectStatus and projectStatus != '':
                queryset_sql_str += f' projectStatus = {projectStatus},'
            if createStartTime and createStartTime != '':
                queryset_sql_str += f"createTime__gte = {createStartTime}, createTime__lte = {get_time() if createEndTime is None and createEndTime == '' else createEndTime},"

            queryset_sql_str += ')'

            queryset = eval(queryset_sql_str)
            serializer = self.serializer_class(queryset, many = True, exclude = self.exclude_fields)
            pageData = Paginator(serializer.data, pageSize)
            data = {
                'pageCount': pageData.count,
                'pageIndex': pageIndex,
                'pageSize': pageSize,
                'list': pageData.page(pageIndex).object_list
            }

            return SuccessResponse(result = data)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectEditAPIView(ProjectBaseAPIView):
    """
    项目新增
    """

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/edit', summary = '项目编辑')
    @APIDOC_DECORATOR.ApiParams(value = 'projectId', type = 'int', require = True, desc = '项目Id')
    @APIDOC_DECORATOR.ApiParams(value = 'projectName', require = True, type = 'string', desc = '项目名称')
    @APIDOC_DECORATOR.ApiParams(value = 'projectIcon', require = False, type = 'string', desc = '项目图标')
    @APIDOC_DECORATOR.ApiParams(value = 'projectDesc', require = False, type = 'string', desc = '项目描述')
    @APIDOC_DECORATOR.ApiParams(value = 'projectStatus', require = False, type = 'int', desc = '项目状态',
                                remark = get_enum_str_list(enumObj = ProjectStatusEnums))
    @APIDOC_DECORATOR.ApiParams(value = 'beginTime', require = False, type = 'int', desc = '项目开始时间', remark = '时间戳')
    @APIDOC_DECORATOR.ApiParams(value = 'endTime', require = False, type = 'int', desc = '项目结算时间', remark = '时间戳')
    @APIDOC_DECORATOR.ApiParams(value = 'remark', type = 'string', desc = '备注')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()

            # 1. 根据ProjectId判断项目是否存在
            queryset_id = self.Model.objects.filter(id = body.get('projectId'), deleted = False)
            if queryset_id.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)
            # 2. 判断projectName是否存在
            queryset_project_name = self.Model.objects.filter(id = body.get('projectName'), deleted = False)
            if queryset_project_name.count() != 0 and queryset_id.first().projectName != body.get('projectName'):
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_NAME_IS_EXIST)
            # 3. 更新
            with transaction.atomic():
                queryset_id.update(
                    projectName = body.get('projectName'),
                    projectIcon = body.get('projectIcon') if body.get(
                        'projectIcon') else queryset_id.first().projectIcon,
                    projectDesc = body.get('projectDesc') if body.get(
                        'projectDesc') else queryset_id.first().projectDesc,
                    projectStatus = body.get('projectStatus') if body.get(
                        'projectStatus') else queryset_id.first().projectStatus,
                    beginTime = body.get('beginTime') if body.get('beginTime') else queryset_id.first().beginTime,
                    endTime = body.get('endTime') if body.get('endTime') else queryset_id.first().endTime,
                    remark = body.get('remark') if body.get('remark') else queryset_id.first().remark,
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectDeleteAPIView(ProjectBaseAPIView):
    """
    项目新增
    """

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/delete', summary = '项目删除')
    @APIDOC_DECORATOR.ApiParams(value = 'projectId', type = 'int', require = True, desc = '项目Id')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()

            # 1. 根据ProjectId判断项目是否存在
            queryset_id = self.Model.objects.filter(id = body.get('projectId'), deleted = False)
            if queryset_id.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)
            # 2. 更新
            with transaction.atomic():
                queryset_id.update(
                    deleted = True,
                    deleteTime = get_time(),
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectCloseAPIView(ProjectBaseAPIView):
    """
    项目关闭
    """

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/delete', summary = '项目关闭')
    @APIDOC_DECORATOR.ApiParams(value = 'projectId', type = 'int', require = True, desc = '项目Id')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()

            # 1. 根据ProjectId判断项目是否存在
            queryset_id = self.Model.objects.filter(id = body.get('projectId'), deleted = False)
            if queryset_id.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)
            # 2. 更新
            with transaction.atomic():
                queryset_id.update(
                    projectStatus = ProjectStatusEnums.CLOSE.key,
                    closedBy = userName,
                    closedTime = get_time(),
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectArrayAPIView(ProjectBaseAPIView):
    serializer_class = ProjectListSerializer

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/array', summary = '进行中项目列表')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()
            isSuper = RequestAuthTokenUtil(request).get_token_into().get('isSuper')
            if isSuper:
                data = queryDict(
                    sql = f"SELECT T2.id, T2.projectName, T2.projectDesc, T2.projectStatus, "
                          f"T2.remark, T2.createTime, T2.creatorId, T2.creatorName FROM tproject T2 "
                          f"WHERE T2.deleted = FALSE AND T2.projectStatus IN (102, 103) "
                          f"ORDER BY T2.createTime DESC")
            else:
                data = queryDict(
                    sql = f"SELECT T2.id, T2.projectName, T2.projectDesc, T2.projectStatus, "
                          f"T2.remark, T2.createTime, T2.creatorId, T2.creatorName FROM tprojectperson T1 "
                          f"INNER JOIN tproject T2 ON T2.id = T1.projectId AND T2.projectStatus IN (102, 103) "
                          f"AND T2.deleted = FALSE "
                          f"WHERE T1.personId = {userId} AND T1.deleted = FALSE "
                          f"ORDER BY T2.createTime DESC ")

            return SuccessResponse(result = data)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectStatisticsAPIView(ProjectBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/statistic', summary = '项目统计')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:

            data = dict(
                planing = self.Model.objects.filter(projectStatus = 101, deleted = False).count(),
                starting = self.Model.objects.filter(projectStatus = 102, deleted = False).count(),
                noStart = self.Model.objects.filter(projectStatus = 103, deleted = False).count(),
                delay = self.Model.objects.filter(projectStatus = 104, deleted = False).count(),
                hang = self.Model.objects.filter(projectStatus = 105, deleted = False).count(),
                finish = self.Model.objects.filter(projectStatus = 105, deleted = False).count(),
                close = self.Model.objects.filter(projectStatus = 106, deleted = False).count(),
            )

            return SuccessResponse(result = data)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectPersonArrayAPIView(ProjectBaseAPIView):
    serializer_class = ProjectListSerializer

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/personArray', summary = '项目成员列表')
    @Authentication(isProject = True)
    def post(self, request, *args, **kwargs):
        try:

            projectId = RequestAuthTokenUtil(request = request).get_project()

            queryset_project = self.Model.objects.filter(deleted = False, id = projectId)
            if queryset_project.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)

            project = queryset_project.first()

            if project:
                queryset = ProjectPerson.objects.filter(projectId = project.id, deleted = False)
                personIds = []
                for i in queryset:
                    personIds.append(i.personId)
                queryset_person = Person.objects.filter(id__in = personIds, deleted = False)
                serializer = PersonListSerializer(queryset_person, many = True)
                return SuccessResponse(result = serializer.data)
            else:
                return SuccessResponse(result = [])
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class ProjectPersonListAPIView(ProjectBaseAPIView):
    serializer_class = ProjectListSerializer

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'project', desc = '项目管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/project/personArray', summary = '项目成员列表')
    @APIDOC_DECORATOR.ApiParams(value = 'projectId', type = 'int', require = True, desc = '项目Id')
    @Authentication(isProject = False)
    def post(self, request, *args, **kwargs):
        try:

            projectId = request.data.get('projectId')

            queryset_project = self.Model.objects.filter(deleted = False, id = projectId)

            if queryset_project.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.PROJECT_ID_IS_NOT_EXIST)

            project = queryset_project.first()
            if project:
                queryset = ProjectPerson.objects.filter(projectId = project.id, deleted = False)
                personIds = []
                for i in queryset:
                    personIds.append(i.personId)
                queryset_person = Person.objects.filter(id__in = personIds, deleted = False)
                serializer = PersonListSerializer(queryset_person, many = True)
                return SuccessResponse(result = serializer.data)
            else:
                return SuccessResponse(result = [])
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


urlpatterns = [
    path('add', ProjectAddAPIView.as_view()),
    path('addPerson', ProjectAddPersonAPIView.as_view()),
    path('list', ProjectListAPIView.as_view()),
    path('edit', ProjectEditAPIView.as_view()),
    path('delete', ProjectDeleteAPIView.as_view()),
    path('close', ProjectCloseAPIView.as_view()),
    path('array', ProjectArrayAPIView.as_view()),
    path('statistic', ProjectStatisticsAPIView.as_view()),
    path('personArray', ProjectPersonArrayAPIView.as_view()),
    path('personList', ProjectPersonListAPIView.as_view()),
]
